package com.example.java_gobang.game;

import com.example.java_gobang.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
@Component
// 这个类表示 “匹配器”，通过这个类负责完成整个匹配功能
public class Matcher {
    // 创建三个匹配队列
    private Queue<User> normalQueue = new LinkedList<>();
    private Queue<User> highQueue = new LinkedList<>();
    private Queue<User> veryHighQueue = new LinkedList<>();

   @Autowired
    private OnlineUserManager onlineUserManager;

    @Autowired
    private RoomManager romManager;

   private ObjectMapper objectMapper = new ObjectMapper();

   // 操作匹配队列的方法
    public  void add (User user) {
        if (user.getScore() < 2000)  {
            synchronized (normalQueue){
                normalQueue.offer(user);
                normalQueue.notify();
            }

            System.out.println("把玩家" + user.getUsername() + "加入到了normalQueue中");

        } else if (user.getScore() >= 2000 && user.getScore() < 3000) {
            synchronized (highQueue) {
                highQueue.offer(user);
                highQueue.notify();
            }

            System.out.println("把玩家" + user.getUsername() + "加入到highQueue中");
        } else {
            synchronized (veryHighQueue) {
                veryHighQueue.offer(user);
                veryHighQueue.notify();
            }

            System.out.println("把玩家" + user.getUsername() + "加入到very加入到highQueue中");
        }
    }
//    当玩家停止点击停止匹配的时候，就需要把玩家从匹配队列中过删除
    public void remove (User user) {
        if (user.getScore() < 2000) {
            synchronized (normalQueue) {
                normalQueue.remove(user);
            }
            System.out.println("把玩家" + user.getUsername() + "移除了normaQUeue");


        }  else if (user.getScore() >= 2000 && user.getScore() < 3000) {
            synchronized (highQueue){
                highQueue.remove(user);
            }
            System.out.println("把玩家" + user.getUsername() + "移除了highQueue");

        } else {
            synchronized (veryHighQueue) {
                veryHighQueue.remove(user);
            }
            System.out.println("把玩家" + user.getUsername() + "移除了veryhighQueue");

        }

    }

    public Matcher () {
        // 创建三个线程，分别针对这三个匹配对列，进行操作
        Thread t1 = new Thread() {
            @Override
            public void run() {
                // 扫描normaQueue
                while(true) {
                    handlerMatch(normalQueue);
                }
            }
        };
        t1.start();

        Thread t2 = new Thread() {
            @Override
            public void run() {
                while (true) {
                    handlerMatch(highQueue);
                }
            }
        };
        t2.start();


        Thread t3 = new Thread() {
            @Override
            public void run() {
                while (true) {
                    handlerMatch(veryHighQueue);
                }

            }
        };
        t3.start();



    }

    private void handlerMatch(Queue<User> matchQueue) {
        synchronized (matchQueue) {
            try {
                // 1.检测队列中元素个数是否
                // 队列的初始情况可能是空
                // 如果往队列中添加一个元素,这个时候 我们仍然不能进行后续匹配操作
                // 因此在这里 while 循环检查更合理的~~
                while (matchQueue.size() < 2) {
                    // 当玩家数量少于两个的时候直接return
                    matchQueue.wait();
                }
                // 2.尝试从队列中取出两个元素
                User play1 = matchQueue.poll();
                User play2 = matchQueue.poll();
                System.out.println("匹配出两个玩家: " + play1.getUsername() + "," + play2.getUsername());
                // 3.获取到玩家的websocket的会话
                // 获取到会话的目的是为了告诉玩家，你排到了~
                WebSocketSession session1 = onlineUserManager.getFromGameHall(play1.getUserId());
                WebSocketSession session2 = onlineUserManager.getFromGameHall(play2.getUserId());
                System.out.println("玩家1: userId:" + play1.getUserId());
                System.out.println("玩家2: userId:" + play2.getUserId());

                // 理论来说， 匹配队列中的玩家一定是在线的状态
                // 因为前面的逻辑进行了处理 当玩家
                if (session1 == null) {
                    // 如果玩家1 现在不在线了 就把玩家二重新放回到匹配队队列
                    matchQueue.offer(play2);
                    return;

                }
                if (session2 == null) {
                    // 如果玩家2现在不在线了 就把玩家二重新放回到匹配队队
                    matchQueue.offer(play1);
                    return;
                }
                // 当前是否排到两个玩家是否是同一个用户的情况嘛 一个玩家入队列了两次
                // 理论上也不会存在
                // 1 如果玩家下线 就会有玩家移除匹配队列
                // 2 又禁止了玩家多开
                // 但是仍然在这里多进行了一次判定 以免前面的逻辑出现bug时带来严重的错误
                if (session1 == session2) {
                    // 把其中的一个玩家放到匹配队列
                    matchQueue.offer(play1);
                    return;
                }

                // TODO 4.把这两个玩家放到一个游戏房间中
                    Room room = new Room();
                    romManager.add(room,play1.getUserId(),play2.getUserId());

                // 5. 给玩家反馈信息，你匹配到对手了
                // 通过 websocket 返回一个 message 为 ‘matchSuccess’这样的响应
                // 此处是给两个玩家返回"匹配成功"这样的信息
                // 因此需要返回两次
                MatchResponse response1 = new MatchResponse();
                response1.setOk(true);
                response1.setMessage("matchSuccess");
                String json1 = objectMapper.writeValueAsString(response1);
                session1.sendMessage(new TextMessage(json1));

                MatchResponse response2 = new MatchResponse();
                response2.setOk(true);
                response2.setMessage("matchSuccess");
                String json2 = objectMapper.writeValueAsString(response2);
                session2.sendMessage(new TextMessage(json2));
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }

        }


    }


}


